package rjp.map;

import gnu.trove.map.hash.TIntFloatHashMap;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

/**
 *
 * @author mwh
 */
public class SantaMap {

    final TIntFloatHashMap xs;

    final TIntFloatHashMap ys;

    final float maxX;

    final float maxY;

    final float minX;

    final float minY;
    
    public SantaMap(TIntFloatHashMap xs, TIntFloatHashMap ys,
            float maxX, float maxY, float minX, float minY) {
        this.xs = xs;
        this.ys = ys;
        this.maxX = maxX;
        this.maxY = maxY;
        this.minX = minX;
        this.minY = minY;

    }
    
    public SantaMap(String fn) throws IOException {
        BufferedReader reader = new BufferedReader(new FileReader(fn));
        String line;
        reader.readLine();
        int maxIndex = Integer.MIN_VALUE;
        while ((line = reader.readLine()) != null) {
            String[] fields = line.split(",");
            maxIndex = Math.max(maxIndex, Integer.parseInt(fields[0]));
        }
        reader.close();
        xs = new TIntFloatHashMap(maxIndex + 1);
        ys = new TIntFloatHashMap(maxIndex + 1);

        reader = new BufferedReader(new FileReader(fn));

        reader.readLine();
        float maX = Float.NEGATIVE_INFINITY;
        float maY = Float.NEGATIVE_INFINITY;
        float miX = Float.POSITIVE_INFINITY;
        float miY = Float.POSITIVE_INFINITY;
        while ((line = reader.readLine()) != null) {
            String[] fields = line.split(",");
            int index = Integer.parseInt(fields[0]);
            float x = Float.parseFloat(fields[1]);
            float y = Float.parseFloat(fields[2]);
            xs.put(index, x);
            ys.put(index, y);

            maX = Math.max(maX, x);
            maY = Math.max(maY, y);
            miX = Math.min(miX, x);
            miY = Math.min(miY, y);

        }
        maxX = maX;
        maxY = maY;
        minX = miX;
        minY = miX;
        reader.close();
    }



    public float getX(int index) {
        return xs.get(index);
    }


    public float getY(int index) {
        return ys.get(index);
    }


    public float getDistance(int indexA, int indexB) {
    	if(indexA==indexB)
    	{
    		return 0;
    	}
        float xdist = getX(indexA) - getX(indexB);
        float ydist = getY(indexA) - getY(indexB);

        return (float) Math.sqrt(xdist * xdist + ydist * ydist);
    }
    

    public float getPathLength(List<Integer> path) {
        float l = 0;
        for (int i=1; i<path.size(); i++) {
            int indexA = path.get(i-1);
            int indexB = path.get(i);
            l = l + getDistance(indexA, indexB);
        }
        return l;
    }


    public int size() {
        return xs.size();
    }
    
    
    
	public int getClosestInSet(int index, Set<Integer> allowed)
	{
		Iterator<Integer> it=allowed.iterator();
		int closest=it.next();
		float minDist=this.getDistance(index, closest);
		while(it.hasNext())
		{
			int city=it.next();
			if(minDist>this.getDistance(index, city))
			{
				closest=city;
				minDist=this.getDistance(index, city);
			}
		}
		return closest;
	}
	
	public int getClosestInSet(int index, Set<Integer> allowed, Set<Integer> notAllowed) throws Exception
	{
		Iterator<Integer> it=allowed.iterator();
		int closest=-1;
		float minDist=Float.MAX_VALUE;
		while(it.hasNext())
		{
			int city=it.next();
			if(minDist>this.getDistance(index, city) && !notAllowed.contains(new Integer(city)))
			{
				closest=city;
				minDist=this.getDistance(index, city);
			}
		}
		
		if(closest==-1)
		{
			throw new Exception("No close city");
		}
		return closest;
	}
	
}
